﻿namespace OrderServiceLevel1
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Runtime.Serialization.Json;
    using System.Web;
    using log4net;
    using OrderServiceLevel1.Model;
    using OrderServiceLevel1.Repositories;

    public class OrderManagementService : BaseHttpHandler
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(OrderManagementService));
        private const string ApplicationJson = "application/json";
        private readonly Dictionary<string, Action<HttpContextBase>> dispatcher;
        private IRepository repository = new MemoryRepository();

        public OrderManagementService()
        {
            this.dispatcher = new Dictionary<string, Action<HttpContextBase>>();

            this.dispatcher.Add("/SubmitOrder", this.SubmitOrder);
            this.dispatcher.Add("/GetOrders", this.GetOrders);
            this.dispatcher.Add("/GetOrderDetails", this.GetOrderDetails);
            this.dispatcher.Add("/UpdateOrder", this.UpdateOrder);
            this.dispatcher.Add("/AddOrderItem", this.AddOrderItem);
            this.dispatcher.Add("/CancelOrder", this.CancelOrder);
        }

        public IRepository Respository
        {
            set
            {
                this.repository = value;
            }
        }

        public override void ProcessRequest(HttpContextBase context)
        {
            string action = context.Request.Path.Replace("/OrderServiceLevel1", string.Empty);

            if (this.dispatcher.ContainsKey(action))
            {
                this.dispatcher[action](context);
            }
            else
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel1/CancelOrder?orderId={orderId}
        /// </remarks>
        private void CancelOrder(HttpContextBase context)
        {
            try
            {
                int orderId;

                int.TryParse(context.Request.QueryString["orderId"], out orderId);

                log.InfoFormat("[CancelOrder] OrderId: {0}", orderId);

                this.repository.RemoveOrder(orderId);

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.NoContent;
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel1/AddOrderItem?orderId={orderId}&itemId={itemId}&itemPrice={itemPrice}&itemQuantity={itemQuantity}
        /// </remarks>
        private void AddOrderItem(HttpContextBase context)
        {
            try
            {
                double price;
                int quantity;
                Item item = new Item();
                int orderId;
                int.TryParse(context.Request.QueryString["orderId"], out orderId);

                Order order = this.repository.RetrieveOrder(orderId);

                double.TryParse(context.Request.QueryString["itemPrice"], out price);
                int.TryParse(context.Request.QueryString["itemQuantity"], out quantity);

                item.Id = context.Request.QueryString["itemId"];
                item.Price = price;
                item.Quantity = quantity;

                order.AddItem(item);

                log.InfoFormat("[AddOrderItem] {0}", order);

                this.repository.UpdateOrder(order);

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.NoContent;
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel1/UpdateOrder?orderId={orderId}&orderCurrency={orderCurrency}&orderStatus={orderStatus}&customerName={customerName}&customerEmail={customerEmail}
        /// </remarks>
        private void UpdateOrder(HttpContextBase context)
        {
            try
            {
                bool placed;
                Order order = new Order();
                Customer customer = new Customer();
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Order));
                int orderId;
                int.TryParse(context.Request.QueryString["orderId"], out orderId);

                bool.TryParse(context.Request.QueryString["orderPlaced"], out placed);

                customer.Email = context.Request.QueryString["customerEmail"];
                customer.Name = context.Request.QueryString["customerName"];

                order.Id = orderId;
                order.Currency = context.Request.QueryString["orderCurrency"];
                order.Status = context.Request.QueryString["orderStatus"];
                order.Placed = placed;
                order.Customer = customer;

                log.InfoFormat("[UpdateOrder] OrderId: {0}", order);

                this.repository.UpdateOrder(order);

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                serializer.WriteObject(context.Response.OutputStream, this.repository.RetrieveOrder(order.Id));
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel1/GetOrderDetails?orderId={orderId}
        /// </remarks>
        private void GetOrderDetails(HttpContextBase context)
        {
            try
            {
                int orderId;
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Order));
                int.TryParse(context.Request.QueryString["orderId"], out orderId);
                Order order = this.repository.RetrieveOrder(orderId);

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                log.InfoFormat("[GetOrderDetails]", orderId);

                serializer.WriteObject(context.Response.OutputStream, order);
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel1/GetOrders
        /// </remarks>
        private void GetOrders(HttpContextBase context)
        {
            try
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Order>));

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                log.Info("[GetOrders]");

                serializer.WriteObject(context.Response.OutputStream, this.repository.Orders);
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel1/SubmitOrder?orderCurrency={orderCurrency}&orderStatus={orderStatus}&customerName={customerName}&customerEmail={customerEmail}
        /// </remarks>
        private void SubmitOrder(HttpContextBase context)
        {
            try
            {
                bool placed;
                Order order = new Order();
                Customer customer = new Customer();
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Order));

                bool.TryParse(context.Request.QueryString["orderPlaced"], out placed);

                customer.Email = context.Request.QueryString["customerEmail"];
                customer.Name = context.Request.QueryString["customerName"];

                order.Currency = context.Request.QueryString["orderCurrency"];
                order.Status = context.Request.QueryString["orderStatus"];
                order.Placed = placed;
                order.Customer = customer;

                log.InfoFormat("[SubmitOrder] {0}", order);

                this.repository.AddOrder(order);

                context.Response.ContentType = ApplicationJson;
                context.Response.StatusCode = (int)HttpStatusCode.Created;

                serializer.WriteObject(context.Response.OutputStream, this.repository.RetrieveOrder(order.Id));
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }
    }
}